package cathttp

///
// * 通信协议库
// * 创建于: 2019-7-13
// * 修改于: 2019-7-14
// * 版本: 0.0.1
// ! -----------------
// ? CatListen
// ?  Listen            ->        CatAddr
// *     |                           |
// *     ?-Listen-(network:tcp)- CatTCPAddr --X
// *     X-Listen-(network:udp)- CatUDPAddr --X
// *                                          |
// *                                          TSet: (Addr:CatAddr)
// ?     CatAddr
// *        |- Call:CatAddr.Serve
// *   ┌────X
// *   │    |- G-Get:CatConn
// *   │ CallBack
// *   │-G
// * Buffer
// ? CatClient
// *     |-Buffer
// ! ----------------
// * 定义
// *  G: 调度 X: 链接 E: 错误 J: 跳过 T: 所在类(type)
// *  Set: 设置 Get: 得到 Call: 调用
// *  ?: 分支 [xxx]: 数组 (x:x): 附加关系
// *  -: 流程 |: 流程 |-X: 链接流程 |-E: 错误流程
///
import (
	"fmt"
	"net"
	"time"
)

// CatConn 通信接口
type CatConn struct {
	Size  int64  // * 占用大小
	Data  []byte // * 读取到的数据
	Addr  string
	Close bool                              // * 关闭连接
	Write func(b []byte) (n int, err error) // * 写数据接口
}

// CatAddr 链接类
type CatAddr interface {
	Close() error
	Serve() error
}

// CatTCPAddr TCP链接实现
type CatTCPAddr struct {
	net.Listener
	CallBack func(conn *CatConn)
	buffer   *Buffer
}

// Serve 链接实现
func (Addr *CatTCPAddr) Serve() error {
	defer Addr.Close()
	for {
		// * 等待链接
		conn, err := Addr.Accept()
		if err != nil {
			return err
		}
		// * 处理链接
		go func(conn net.Conn) {
			// * 长链接主循环
			for {
				// * 得到缓冲接口
				buffer := Addr.buffer.Get()
				if Conn, ok := buffer.Value.(*CatConn); ok {
					// * 读数据
					n, err := conn.Read(Conn.Data)
					if err != nil {
						break
					}
					Conn.Size = int64(n)
					Conn.Write = conn.Write
					Conn.Addr = Addr.Addr().String()
					Addr.CallBack(Conn)
					// * 关闭连接
					if Conn.Close {
						break
					}
				}
				// * 调用结束后释放
				buffer.Release()
			}
		}(conn)
	}
}

// CatUDPAddr UDP链接实现
type CatUDPAddr struct {
	*net.UDPConn
	CallBack func(conn *CatConn)
	buffer   *Buffer
}

// Serve 链接实现
func (Addr *CatUDPAddr) Serve() error {
	defer Addr.Close()
	for {
		// * 得到缓冲接口
		buffer := Addr.buffer.Get()
		if Conn, ok := buffer.Value.(*CatConn); ok {
			n, UDPAddr, err := Addr.ReadFromUDP(Conn.Data)
			if err != nil {
				return err
			}
			Conn.Size = int64(n)
			Conn.Write = func(b []byte) (n int, err error) {
				return Addr.WriteToUDP(b, UDPAddr)
			}
			Conn.Addr = Addr.RemoteAddr().String()
			Addr.CallBack(Conn)
			// * 关闭连接
			if Conn.Close {
				break
			}
		}
		// * 调用结束后释放
		buffer.Release()
	}
	return nil
}

// CatListen 链接类
type CatListen struct {
	CatAddr
	CallBack func(conn *CatConn)
	buffer   *Buffer
}

// Listen 链接
func (Listen *CatListen) Listen(network, address string, CallBack func(conn *CatConn)) error {
	// * 设置变量
	Listen.CallBack = CallBack
	// * 缓冲管理器
	if Listen.buffer == nil {
		Listen.buffer = (&Buffer{
			New: func() interface{} {
				return &CatConn{
					// * 缓存大小 2M
					Data: make([]byte, 1024*1024*2),
				}
			},
		}).Init((int64)(time.Minute * 5))
	}
	// * 协议类型判断
	switch network {
	case "tcp", "tcp4", "tcp6", "unix", "unixpacket":
		// * 初始化链接
		tcp, err := net.Listen(network, address)
		if err != nil {
			return fmt.Errorf("初始化链接失败: %v", err)
		}
		// * 设置类型
		Listen.CatAddr = (CatAddr)(&CatTCPAddr{tcp, Listen.CallBack, Listen.buffer})
	case "udp", "udp4", "udp6":
		// * 初始化链接
		addr, err := net.ResolveUDPAddr(network, address)
		if err != nil {
			return fmt.Errorf("初始化链接失败: %v", err)
		}
		udp, err := net.ListenUDP(network, addr)
		if err != nil {
			return fmt.Errorf("初始化链接失败: %v", err)
		}
		// * 设置类型
		Listen.CatAddr = (CatAddr)(&CatUDPAddr{udp, Listen.CallBack, Listen.buffer})
	default:
		return fmt.Errorf("未知协议类型")
	}
	return nil
}

// CatClient 客户端类型
type CatClient struct {
	CallBack func(conn *CatConn)
	buffer   *Buffer
	conn     net.Conn
}

// Dial 链接
func (Client *CatClient) Dial(network, address string, CallBack func(conn *CatConn)) (conn net.Conn, err error) {
	// * 设置变量
	Client.CallBack = CallBack
	// * 缓冲管理器
	if Client.buffer == nil {
		Client.buffer = (&Buffer{
			New: func() interface{} {
				return &CatConn{
					// * 缓存大小 2M
					Data: make([]byte, 1024*1024*2),
				}
			},
		}).Init((int64)(time.Minute * 5))
	}
	// * 连接目标
	Client.conn, err = (&net.Dialer{}).Dial(network, address)
	if err != nil {
		return Client.conn, err
	}
	return Client.conn, nil
}

// Serve 连接
func (Client *CatClient) Serve() error {
	defer Client.conn.Close()
	for {
		// * 得到缓冲接口
		buffer := Client.buffer.Get()
		if Conn, ok := buffer.Value.(*CatConn); ok {
			// * 读数据
			n, err := Client.conn.Read(Conn.Data)
			if err != nil {
				return err
			}
			Conn.Size = int64(n)
			Conn.Write = Client.conn.Write
			Conn.Addr = Client.conn.RemoteAddr().String()
			// * 读回调
			Client.CallBack(Conn)
			// * 关闭连接
			if Conn.Close {
				break
			}
		}
		// * 调用结束后释放
		buffer.Release()
	}
	return nil
}
